//
//	File: OyD3D9FontRender.cpp
//

#include "OyD3D9FontRender.h"
#include "..\OyDirect3D9.h"
#include "..\..\OyRenderer\OyEngine.h"

static unsigned short FONT_index[6] = { 0, 1, 2, 0, 2, 3 };

OyD3D9_FontBuffer::OyD3D9_FontBuffer(LPDIRECT3DTEXTURE9 pTexture, LPDIRECT3DDEVICE9 pDevice, OyDirect3D9 *pOyD3D9)
{
	HRESULT hr;
	m_pTexture = pTexture;
	m_pDevice = pDevice;
	m_nNumTris = 0;

	m_pDecl = pOyD3D9->GetVertexDeclaration(VID_FONT);


	// create the buffers
	m_pVB = NULL;
	m_pIB = NULL;

	hr = m_pDevice->CreateVertexBuffer(	sizeof(OY_FONT_VERTEX_TYPE) * MAX_CHAR_IN_BUFFER * 4,
										D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
										0, D3DPOOL_DEFAULT, 
										&m_pVB, NULL);
	if(FAILED(hr))
		m_pVB = NULL;

	hr = m_pDevice->CreateIndexBuffer(	sizeof(WORD) * MAX_CHAR_IN_BUFFER * 6,
										D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
										D3DFMT_INDEX16, 
										D3DPOOL_DEFAULT, &m_pIB, NULL);
	if(FAILED(hr))
		m_pIB = NULL;

	m_pCachedVertex = new OY_FONT_VERTEX_TYPE [MAX_CHAR_IN_BUFFER*4];
	m_pCachedIndex = new WORD [MAX_CHAR_IN_BUFFER*6];
}

OyD3D9_FontBuffer::~OyD3D9_FontBuffer()
{
	if( m_pVB )
		m_pVB->Release();
	if( m_pIB )
		m_pIB->Release();
	m_pVB = NULL; 
	m_pIB = NULL;

	delete [] m_pCachedVertex;
	delete [] m_pCachedIndex;
	m_pCachedVertex = NULL;
	m_pCachedIndex = NULL;
}

void OyD3D9_FontBuffer::OnDeviceLost()
{
	if( m_pVB )
		m_pVB->Release();
	if( m_pIB )
		m_pIB->Release();
	m_pVB = NULL; 
	m_pIB = NULL;
}

void OyD3D9_FontBuffer::OnDeviceReset()
{
	HRESULT hr;
	hr = m_pDevice->CreateVertexBuffer(	sizeof(OY_FONT_VERTEX_TYPE) * MAX_CHAR_IN_BUFFER * 4,
										D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
										0, D3DPOOL_DEFAULT, 
										&m_pVB, NULL);
	if(FAILED(hr))
		m_pVB = NULL;

	hr = m_pDevice->CreateIndexBuffer(	sizeof(WORD) * MAX_CHAR_IN_BUFFER * 6,
										D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY,
										D3DFMT_INDEX16, 
										D3DPOOL_DEFAULT, &m_pIB, NULL);
	if(FAILED(hr))
		m_pIB = NULL;

	//////////////////////////////////////////////////////////////////////////////////
	BYTE *tmp_pVerts = NULL;
	WORD *tmp_pIndis = NULL;

	if( FAILED(m_pVB->Lock(0, sizeof(OY_FONT_VERTEX_TYPE) * MAX_CHAR_IN_BUFFER * 4, (void**)&tmp_pVerts, D3DLOCK_DISCARD)))
		return;
	if( FAILED(m_pIB->Lock(0, sizeof(WORD) * MAX_CHAR_IN_BUFFER * 6, (void**)&tmp_pIndis, D3DLOCK_DISCARD))) 
	{
		m_pVB->Unlock();
		return;
	}

	memcpy(tmp_pVerts, m_pCachedVertex, sizeof(OY_FONT_VERTEX_TYPE)*MAX_CHAR_IN_BUFFER*4);
	memcpy(tmp_pIndis, m_pCachedIndex, sizeof(WORD)*MAX_CHAR_IN_BUFFER*6);

	m_pVB->Unlock();
	m_pIB->Unlock();
}

void OyD3D9_FontBuffer::PushVertex(OY_FONT_VERTEX_TYPE FourVerts[4])
{
	m_pCachedVertex[m_nNumTris*2 + 0] = FourVerts[0];
	m_pCachedVertex[m_nNumTris*2 + 1] = FourVerts[1];
	m_pCachedVertex[m_nNumTris*2 + 2] = FourVerts[2];
	m_pCachedVertex[m_nNumTris*2 + 3] = FourVerts[3];

	for( UINT i=0; i<6; i++ )
		m_pCachedIndex[m_nNumTris*3+i] = WORD(FONT_index[i] + m_nNumTris*2);

	m_nNumTris += 2;
}

HRESULT	OyD3D9_FontBuffer::Flush()
{
	HRESULT hr = OY_OK;
	if( m_nNumTris == 0 )
		return hr;

	if( m_pVB == NULL || m_pIB == NULL )
		return OY_CREATEBUFFER;

	BYTE *tmp_pVerts = NULL;
	WORD *tmp_pIndis = NULL;

	if( FAILED(m_pVB->Lock(0, sizeof(OY_FONT_VERTEX_TYPE)*m_nNumTris*2, (void**)&tmp_pVerts, D3DLOCK_DISCARD)))
		return OY_BUFFERLOCK;
	if( FAILED(m_pIB->Lock(0, sizeof(WORD)*m_nNumTris*3, (void**)&tmp_pIndis, D3DLOCK_DISCARD))) 
	{
		m_pVB->Unlock();
		return OY_BUFFERLOCK;
	}

	memcpy(tmp_pVerts, m_pCachedVertex, sizeof(OY_FONT_VERTEX_TYPE)*m_nNumTris*2);
	memcpy(tmp_pIndis, m_pCachedIndex, sizeof(WORD)*m_nNumTris*3);

	m_pVB->Unlock();
	m_pIB->Unlock();

	hr = m_pDevice->SetVertexDeclaration(m_pDecl);
	hr = m_pDevice->SetStreamSource(0, m_pVB, 0, sizeof(OY_FONT_VERTEX_TYPE));
	hr = m_pDevice->SetIndices(m_pIB);
	hr = m_pDevice->SetTexture(0, m_pTexture);
	hr = m_pDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, m_nNumTris*2, 0, m_nNumTris );
	
	// Clear this Buffer
	m_nNumTris = 0;

	return hr;
}